/**
 * Battleship game
 */

/* Global variables */
var SQR_SIZE = 42; 			// px
var placedFleets = [];
var player = null; 			// Player Object
var enemy = null;			// Player Object
var whosTurn = 0;
var game, canvas, move;
var localGameId = -1;
var gameEnded = false;
var canFire = true;
var fleets = [          
    {count: 1, size: 4, name : "Sõjalaev"},
    {count: 2, size: 3, name : "Ristleja"},
    {count: 3, size: 2, name : "Hävitaja"},
    {count: 4, size: 1, name : "Allveelaev"}
];

$(document).bind("dragstart", function() {
	return false;
});

$(document).ready(function(){
	if (!document.createElement('audio')) {
		console.log('html5 audio element is not supported ');
	}
	Sound.init();

	/* Initialize canvas */
	canvas = Canvas();
	canvas.drawTable();
	
	var s = String(window.location);
	if (s.indexOf("game.jsp") != -1) {
		canvas.autoPlace();
		AjaxRequest.getPlayerID();
		localGameId = Replay.getLocalGameNumber();
		$("#game a.start-game").bind('click', function(){
			game = Game();
			game.start();
		});
	} else if (s.indexOf("lobby.jsp") != -1) {
		AjaxRequest.newPlayer();
	} else {
		Replay.initReplay();
		$("#game a.start-game").bind('click', function(){
			Replay.startReplay();
		});
	}
});

var Sound = {
	missed : null,
	hit : null,
	sinked : null,
	
	init : function() {
		Sound.missed = document.createElement('audio');
		Sound.missed.setAttribute('src', './files/missed.wav');
		Sound.missed.setAttribute('type', 'audio/wav');
		
		Sound.hit = document.createElement('audio');
		Sound.hit.setAttribute('src', './files/bigboom.wav');
		Sound.hit.setAttribute('type', 'audio/wav');
		
		Sound.sinked = document.createElement('audio');
		Sound.sinked.setAttribute('src', './files/sinked.mp3');
		Sound.sinked.setAttribute('type', 'audio/mp3');
	},
	
	playMissed : function() {
		Sound.missed.play();
	},
	
	playHit : function() {
		Sound.hit.play();
	},
	
	playSinked : function() {
		Sound.sinked.play();
	}
};

/* Fleet object */
var Fleet = function(id, size, name){
	this.id = id;
	this.size = size;
	this.name = name;
	this.orientation = 0;
	this.top = 0;
	this.left = 0;
	this.health = size;

	this.setTopLeft = function(top, left){
		this.top = top;
		this.left = left;
	};
	
	this.setOrientation = function(orientation){
		this.orientation = orientation;
	};
};

/* Player object */
var Player = function(id){
	this.id = id;
	this.hit = 0;			// hits
	this.total = 0;			// total shots
	this.sinked = 0;		// sinked ships
};

var Canvas = function(){
	var canvas = $("#canvas");
	var enemy = $("#enemy");
	
	move = new Move();
	
	/* Attaching handlers */
	$(document).bind("mousemove", move.mouseMove);

	canvas.delegate(".fleet", "mousedown", function(){
		move.drag(this);
	});
	
	canvas.delegate(".fleet", "mouseup", function(){
		move.drop();
	});
	
	canvas.delegate(".fleet","dblclick", function(){
		move.rotate(placedFleets[this.id]);
	});
	
	$(".autoPlace").bind('click', function(e){
		autoPlace();
		e.preventDefault();
		return false;
	});
	
	$(".block").bind('click', function(e){
		e.preventDefault();
		return false;
	});
	
	/* View functions */
	var drawTable = function(){
		for(var i=0;i<100;i++){	
			canvas.append('<div class="block"></div>');
		}
	};
	
	var drawEnemyTable = function(){
		$(".enemytext").remove();
		for(var i=0;i<10;i++){	
			for(var j=0;j<10;j++){
				enemy.append('<a href="javascript:void(0)" id="enemy' + j + '' + i +'" class="block" onclick="game.fire(' + j + ', ' + i +')"></a>');
			}		
		}
		
		drawGameElements();
	};
	
	var drawFleets = function(){
		for(var placed in placedFleets){
			var fleet = placedFleets[placed];
			drawFleet("fleet", "normal", fleet, null);
		}
	};
	
	var drawFleet = function(name, type, fleet, subject){
		var fleetDiv = $('<div id="' + name + '' + fleet.id +'" class="fleet"></div>');
		var fleetImagePosition;
		if(type == "normal"){
			fleetImagePosition = calculateFleetImagePosition(fleet);
		} else if (type == "sinked"){
			fleetImagePosition = calculateSinkedFleetImagePosition(fleet);
		}

		fleetDiv.css({
			'top'	: parseInt(fleet.top * SQR_SIZE + 1) + 'px',
			'left'	: parseInt(fleet.left * SQR_SIZE + 1) + 'px',
			'width'	: width = (fleet.orientation == 1) ? (fleet.size * SQR_SIZE) + 'px' : SQR_SIZE + 'px',
			'height': height = (fleet.orientation == 0) ? (fleet.size * SQR_SIZE) + 'px' : SQR_SIZE + 'px',
			'background-image' : 'url(gfx/' + fleetImagePosition.img + ')',
			'background-repeat' : 'no-repeat',
			'background-position' :  (fleetImagePosition.left+1) +'px ' + (fleetImagePosition.top+1) + 'px',
		});
		
		if(subject != null && subject == "enemy"){
			enemy.append(fleetDiv);
		} else {
			canvas.append(fleetDiv);
			if(type == "sinked"){
				$("#fleet"+fleet.id).remove();
			}
		}
	};
	
	var autoPlace = function(){
		$("#loading").show();
		$(".autoPlace").unbind('click', function(){
			return false;
		});
		
		placedFleets = generateFleets();
		$(".fleet").remove(); 
		drawFleets();
		$("#loading").fadeOut('fast');
		return false;
	};
	
	var generateFleets = function(){
		var fleetObjects = [];
		var index = 1;
		var failedAttempts = 0;
		
		for(var i = 0; i < fleets.length; i++){
			var count = fleets[i].count;
			for(var j = 0; j < count; j++){
				var conflict = true;
				
				var fleet = new Fleet(index, fleets[i].size, fleets[i].name);
				
				while(conflict){
					/* Prevent infinite loop when limit of failed attempts exceeded. */
					if(failedAttempts > 100){
						return generateFleetPos();	
					}
					var top = randomInt(0,9);
					var left = randomInt(0,9);
					var orientation = randomInt(0,1);
					
					fleet.setTopLeft(top, left);
					fleet.setOrientation(orientation);
					var valid = validatePos(fleet, fleetObjects);
					if(valid){
						fleetObjects["fleet"+fleet.id] = fleet;
						conflict = false;
					} else {
						failedAttempts++;
					}
				}
				index++;
			}
		}
		
		return fleetObjects;
	};
	
	var drawGameElements = function(){
		$("#buttons").children().remove();
		$("#buttons").append('<div class="score">0</div>');
		$("#buttons").append('<div class="whos_turn"></div>');
		$("#buttons").append('<div class="enemy-score">0</div>');
	};
	
	var displayWhosTurn = function(){
		$(".whos_turn").html("");
		if(whosTurn == 1){
			$(".whos_turn").removeClass('red').addClass('green');
			$(".whos_turn").html("Sinu kord");
		} else {
			$(".whos_turn").removeClass('green').addClass('red');
			$(".whos_turn").html("Vastase kord");
		}
	};
	
	var drawShot = function(type, name, x, y, subject){
		var shot;
		if(type == "hit"){
			shot = $('<div id="' + name +'' +  x +  '' + y + '" class="hit"></div>');
		} else if(type == "missed"){
			shot = $('<div class="missed"></div>');
		}
		
		shot.css({'left' : (x * 42 + 1) + 'px', 'top' : (y * 42 + 1) + 'px'});
		
		if(subject != "enemy"){
			canvas.append(shot);
		} else {
			enemy.append(shot);
		}
	};
	
	var removeHitShots = function(name, fleet){
		var width = (fleet.orientation == 1) ? fleet.size : 1;
		var height = (fleet.orientation == 0) ? fleet.size : 1;
		var i, j;
		
		for(i = fleet.left; i < (fleet.left+width); i++){
			for(j = fleet.top; j < (fleet.top+height); j++){
				$("#"+ name + "" + i + "" + j).remove();
			}
		}
	};
	
	var displayScore = function(subject, score){
		if(subject != "enemy"){
			$(".score").text(score);
		} else {
			$(".enemy-score").text(score);
		}
	};
	
	var displayError = function(message){
		$("#error").text(message);
		$("#error").fadeIn(10, function(){
			$("#error").fadeOut('slow');
		});
	};
	
	var displayEnemyLeft = function(message) {
		$("#enemy").empty();
		$("#enemy").append('<div class="enemy-left-message">Vastane on lahkunud mängust. Mine <a href="lobby.jsp">tagasi</a> ja proovi uuesti.</div>');
	};
	
	return {
		drawTable : drawTable,
		drawEnemyTable : drawEnemyTable,
		drawFleets : drawFleets,
		autoPlace : autoPlace,
		displayWhosTurn : displayWhosTurn,
		drawFleet : drawFleet,
		drawShot : drawShot,
		removeHitShots : removeHitShots,
		displayScore : displayScore,
		displayError : displayError,
		displayEnemyLeft : displayEnemyLeft
	};
};

var Move = function(){
	var dragObject = null; 		// DOM element
	var dragFleet = null; 		// Fleet object
	isListening = true; 		// default
	
	var mouseMove = function(e){
		mouseXY = getMouseXY(e);
		if(dragObject != null){
			if(dragFleet != null){
				if(dragFleet.orientation == 0){
					if((mouseXY.y - dragTopDiff)<(420 - (dragFleet.size * 42)) && (mouseXY.y - dragTopDiff)>0){
						dragObject.style.top = (mouseXY.y - dragTopDiff) + 'px';
					}
					if((mouseXY.x - dragLeftDiff)<378 && (mouseXY.x - dragLeftDiff)>0){
						dragObject.style.left = (mouseXY.x - dragLeftDiff) + 'px';
					}
				} else if(dragFleet.orientation == 1){
					if((mouseXY.x - dragLeftDiff)<(420 - (dragFleet.size * 42)) && (mouseXY.x - dragLeftDiff)>0){
						dragObject.style.left = (mouseXY.x - dragLeftDiff) + 'px';
					}
					if((mouseXY.y - dragTopDiff)<378 && (mouseXY.y - dragTopDiff)>0){
						dragObject.style.top = (mouseXY.y - dragTopDiff) + 'px';
					}
				}
			}
		}
		
	return false;
	};
	
	var drag = function(target){

		if(!isListening){
			return;
		}
		
		if(dragObject != null){
			return;
		}
		
		if(placedFleets[target.id] == null){
			return;
		}
		
		/* Fleet object */
		dragFleet = placedFleets[target.id];
		/* DOM element */
		dragObject = target;
		
		prevTop = parseInt(dragObject.style.top);
		prevLeft = parseInt(dragObject.style.left);
			
		dragTopDiff = mouseXY.y - prevTop;
		dragLeftDiff = mouseXY.x - prevLeft;
	};
		
	var drop = function(){
		if(!isListening){
			return;
		}

        dragFleet.setTopLeft(Math.round(parseInt(dragObject.style.top) / 42), Math.round(parseInt(dragObject.style.left) / 42));
		
		dragObject.style.top = ((dragFleet.top*42)+1) + 'px';
		dragObject.style.left = ((dragFleet.left*42)+1) + 'px';
        
        if(validatePos(dragFleet, placedFleets)==false){
                dragFleet.setTopLeft((prevTop-1)/42, (prevLeft-1)/42);
                dragObject.style.top = prevTop + 'px';
                dragObject.style.left = prevLeft + 'px';
				canvas.displayError("Ei saa asetada");
        }
		
        dragFleet = null;
        dragObject = null;
	};

	var getMouseXY = function(e){
		if(!e) var e = window.event;
		if(e.pageX || e.pageX == 0){
	        posX = e.pageX + document.body.scrollLeft;
	        posY = e.pageY + document.body.scrollTop;
		} else if(e.clientX || e.clientX == 0){
			posX = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
	        posY = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
		}
		
		return {x : posX, y : posY};
	};
	

	var rotate = function(fleetObject){
		if(fleetObject != null){
			var position = calculateFleetImagePosition(fleetObject);
			fleetObject.orientation = (fleetObject.orientation == 1) ? 0 : 1;
			
			if(validatePos(fleetObject, placedFleets) == false){
				fleetObject.orientation = (fleetObject.orientation == 0) ? 1 : 0;
				canvas.displayError("Ei saa pöörata");
				return;
			}
			
			var image = (fleetObject.orientation == 0) ? 'laevad-v.png' : 'laevad-h.png';
			
			$("#fleet" + fleetObject.id).css({
				'width'	: width = (fleetObject.orientation == 1) ? (fleetObject.size * SQR_SIZE) + 'px' : SQR_SIZE + 'px',
				'height': height = (fleetObject.orientation == 0) ? (fleetObject.size * SQR_SIZE) + 'px' : SQR_SIZE + 'px',
				'background-image' : 'url(gfx/' + image + ')',
				'background-repeat' : 'no-repeat',
				'background-position' :  (position.top+1) +'px ' + (position.left+1) + 'px',
			});
		}
	};
	
	/* Disable dragging and autoplace */
	var stopListening = function(){
		if (isListening) {
			isListening = false;
			$(".autoPlace").unbind('click');
		}
	};
	
	return {
		drag : drag,
		mouseMove : mouseMove,
		drop : drop,
		rotate : rotate,
		stopListening : stopListening
	};
};

var Game = function(){
	var canvas = Canvas();
	
	var start = function(){	
		move.stopListening();
		AjaxRequest.uploadFleets();

		/* Creating Player objects */
		player = new Player(playerID);
		enemy = new Player(-1);

		canvas.drawEnemyTable();
	};

	var fire = function(x, y){
		if (!canFire) {
			return false;
		}
		
		canFire = false;
		if(whosTurn != 1){
			return false;
		}
		
		AjaxRequest.shoot(x, y);
		
		/* Prevent firing more than one time */
		$("#enemy" + x + "" + y).removeAttr('onclick');
	};
	
	var checkStatus = function(x, y, placedFleets){
		var fleet = null, hit;

		for(var placed in placedFleets){
	        placedPos = calculateLocation(placedFleets[placed].top, placedFleets[placed].left, placedFleets[placed].orientation, placedFleets[placed].size);
	        
	        // 1 = 42 px; 1 square = 42 x 42 px 
	        if(x < (placedPos['x2']) && (x+1) > (placedPos['x1'])){
	        	
	            if(y < (placedPos['y2']) && (y+1) > (placedPos['y1'])){
	            	placedFleets[placed].health--;
	                return {fleet: placedFleets[placed], hit: true};
	            }
			}
		}
		
		return {fleet: fleet, hit: false};
	};
	
	return {
		start : start,
		fire : fire
	};
};

/* Helper functions */

var validatePos = function(fleet, placedFleetObjects){
    var fleetPos = calculateLocation(fleet.top, fleet.left, fleet.orientation, fleet.size);
    if((fleetPos['x2'] > 10 || fleetPos['y2'] > 10) || (fleetPos['x1'] < 0 || fleetPos['y1'] < 0)){
            return false;
    }

    for(var placed in placedFleetObjects){
    	if (placedFleetObjects[placed].id != fleet.id){
    		var placedPos = calculateLocation(placedFleetObjects[placed].top, placedFleetObjects[placed].left, placedFleetObjects[placed].orientation, placedFleetObjects[placed].size);
                if(fleetPos['x1'] < (placedPos['x2'])+1 && fleetPos['x2'] > (placedPos['x1'])-1){
                    if(fleetPos['y1'] < (placedPos['y2'])+1 && fleetPos['y2'] > (placedPos['y1'])-1){
                            return false;
                    }
                }
            }
    }

    return true;
};

var calculateLocation = function(top, left, orientation, size){
	var values = [];
	values['x1'] = left;
	values['y1'] = top;
	if(orientation == 1){
		values['x2'] = left + size;
		values['y2'] = top + 1;
	} else {
		values['x2'] = left + 1;
		values['y2'] = top + size;
	}

	return values;
};

var calculateFleetImagePosition = function(fleetObject){
	var img, top, left;

	if(fleetObject.orientation == 1){
		img = 'laevad-h.png';
		left = 0;
		top = fleetObject.size * 42 - 168; /* 168px whole image size */
	} else {
		img = 'laevad-v.png';
		top = 0;
		left = fleetObject.size * 42 - 168;
	}
	
	return {img: img, top: top, left: left};
};

var calculateSinkedFleetImagePosition = function(fleetObject){
	var img, top, left;

	if(fleetObject.orientation == 1){
		img = 'laevad-uputatud-h.png';
		left = 0;
		top = fleetObject.size * 42 - 168;
	} else {
		img = 'laevad-uputatud.png';
		top = 0;
		left = fleetObject.size * 42 - 168;
	}
	return {img: img, top: top, left: left};
};

var randomInt = function(min, max){
	return min + Math.floor(Math.random()*((max+1) - min));
};